package info.niwota.fwrite;

import info.niwota.commons.web.ContentHelper;
import info.niwota.commons.web.JsonObject;

import java.io.File;
import java.io.FilenameFilter;
import java.io.Serializable;
import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONException;

import android.util.Log;

/**
 * A note (document) consists of id, path, content (doc),
 * 
 * @author qiangli
 *
 */
public class Document implements Serializable {
	private static final String TAG = "Document";
	
	private static final long serialVersionUID = 1L;
	
	public static final FilenameFilter filter = new FilenameFilter() {
		public boolean accept(File dir, String name) {
			return name.endsWith(Document.FILE_EXT);
		}
	};
	
	public static final String KEY_ID = "id";
	//public static final String KEY_PATH = "path";

	public static final String KEY_DOC = "doc";
	public static final String KEY_SUBNOTES = "subnotes";
	public static final String KEY_ORDER = "order";
	
	public static final String KEY_FLAG = "flag";
	public static final String KEY_ALERT = "alert";
	public static final String KEY_TAGS = "tags";
	
	//

	public static final String KEY_CREATED = "created";
	public static final String KEY_MODIFIED = "modified";

	public static final String KEY_PLUS1 = "plus1";
	public static final String KEY_NUMBERED = "numbered";
	public static final String KEY_FLAGGED = "flagged";
	
	public static final String KEY_AUTHOR = "author";
	public static final String KEY_MIMETYPES = "mimetypes";
	public static final String KEY_INTENT = "intent";
	public static final String KEY_BACKGROUND = "background";
	
	//predefined id
	public static final String ID_IMPORTANT = "100";
	public static final String ID_ALERT = "110";
	public static final String ID_TEMPLATE = "120";

	public static final int SORT_NONE = -1;
	
	public static final int SORT_FLAG = 0;
	
	public static final int SORT_DATE = 2;
	
	public static final double FLAG_DEFAULT = 0;
	public static final int ORDER_DEFAULT = SORT_FLAG;
	public static final String FILE_EXT = ".fdoc";
	
	//public static final int TYPE_AUTO = 0;
	
	public static final int TYPE_NOTE = 1;
	
	public static final int TYPE_LIST = 2;
	
	private JsonObject obj;
	
	//
	private String id = null; 

	private File file = null;
	
	private double flag = FLAG_DEFAULT;
	
	private long created = System.currentTimeMillis();
	
	private long modified = created;
	
	private String background = null;
	//
	
	private int order = ORDER_DEFAULT;

	//content doc modified flag
	private boolean changed = false;

	//cached
	private transient File subfolder = null;

	private transient int type = -1;

	public Document(File file) {
		this.file = file;
	}

	public void load() {
		JsonObject obj = null;
		
		if (file != null && file.exists()) {
			try {
				obj = ContentHelper.readObject(file);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			obj = new JsonObject();
		}
		init(obj);
	}
	
	private void init(JsonObject obj) {
		this.obj = obj;
		
		id = obj.getString(KEY_ID, null);
		flag = obj.getDouble(KEY_FLAG, FLAG_DEFAULT);
		order = obj.getInt(KEY_ORDER, ORDER_DEFAULT);
		created = obj.getLong(KEY_CREATED, 0);
		modified = obj.getLong(KEY_MODIFIED, System.currentTimeMillis());
		background = obj.getString(KEY_BACKGROUND, null);
	}
	
	
	public File getSubfolder() {
		if (subfolder != null) {
			return subfolder;
		}
		//
		if (file == null) {
			return null;
		}
		final String p = file.getPath();
		if (!p.endsWith(FILE_EXT)) {
			return null;
		}
		final int len = p.length() - FILE_EXT.length();
		this.subfolder =  new File(p.substring(0, len));
		
		//
		return this.subfolder;
	}
	
	public void show(DocumentView doc) {
		try {
			doc.clear();
			
//			byte[] ba = getContent();
//			if (ba == null) {
//				return;
//			}
			//
			//SDCard.deserializeDoc(new ByteArrayInputStream(ba), doc);
			
			JSONArray ja = obj.getJSONArray(KEY_DOC);
			final int lineCount = ja.length();
			for (int i = 0; i < lineCount; i++) {
				JsonObject jo = new JsonObject(ja.getString(i));
				doc.addLine(new Line(jo));
			}
			
		} catch (Exception e) {
			Log.e(TAG, e.getMessage() + "");
		}
	}

//	private byte[] getContent() throws Exception {
//		if (content != null) {
//			return content;
//		}
//		String s = obj.getString(KEY_DOC);
//		if (s == null) {
//			return null;
//		}
//		byte[] ba = Base64.decode(s);
//		this.content  = ba;
//		return ba;
//	}

	
	public void save(DocumentView dv) throws Exception {
//		
//		ByteArrayOutputStream os = new ByteArrayOutputStream();
//		SDCard.serializeDoc(doc, os);
//		final String enc = Base64.encodeBytes(os.toByteArray());
		
		ArrayList<Line> lines = dv.getLines();
		final int lineCount = lines.size();
		JSONArray ja = new JSONArray();
		for (int i = 0; i < lineCount; i++) {
			ja.put(lines.get(i).toJSON());
		}
		
		obj.put(KEY_DOC, ja);
		obj.put(KEY_FLAG, flag);
		obj.put(KEY_ORDER, order);
		obj.put(KEY_MODIFIED, System.currentTimeMillis());
		if (background != null) {
			obj.put(KEY_BACKGROUND, background);
		}
		ContentHelper.saveObject(obj, file);
		//
		
		this.changed = false;
	}
	
	public void save() throws Exception {
		obj.put(KEY_FLAG, flag);
		obj.put(KEY_ORDER, order);
		obj.put(KEY_MODIFIED, System.currentTimeMillis());
		
		ContentHelper.saveObject(obj, file);
	}
	
	public String getId() {
		return id;
	}

	public double getFlag() {
		return flag;
	}

	public void setFlag(double flag) {
		this.flag = flag;
	}

	public boolean hasAlert() {
		return false;
	}

	public boolean hasAttachment() {
		return false;
	}

	public void delete() {
		if (file != null && file.isFile() && file.getPath().endsWith(FILE_EXT)) {
			file.delete();
			File subfolder = getSubfolder();
			if (subfolder != null && subfolder.exists()) {
				delete(subfolder);
			}
		}
	}
	
	private static void delete(File file) {
		//remove file first
		if (file.isFile()) {
			file.delete();
			return;
		}
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			if (files != null && files.length > 0) {
				for (int i = 0; i < files.length; i++) {
					delete(files[i]);
				}
			}
			file.delete();
		}
	}

	public long getCreated() {
		return created;
	}

	public long getModified() {
		return modified;
	}

	public void setModified(long modified) {
		this.modified = modified;
	}

	public int getOrder() {
		return order;
	}
	
//	public boolean isTop() {
//		return (root);
//	}

	public int getType() {
		if (type != -1) {
			return type;
		}
		//
		type = TYPE_NOTE;
		//expensive but no better way until Java7 ?
		final File sub = getSubfolder();
		if (sub != null && sub.exists()) {
			String[] files = sub.list(filter);
			if (files != null && files.length > 0) {
				type = TYPE_LIST;
			}
		}
		
		return type;
	}

	public boolean isEmpty() {
		try {
			Object ba = getContent();
			return (ba == null);
		} catch (Exception e) {
			Log.e(TAG, e.getMessage() + "");
		}
		return true;
	}

	private JSONArray getContent() throws JSONException {
		return obj.getJSONArray(KEY_DOC);
	}

	public void setBackground(String uri) {
		this.background = uri;
	}
	
	public int getBackground() {
		return isEmpty() ? R.drawable.background_blue : R.drawable.background_black;
	}
	
	public Document getParentDocument() {
		File p = file.getParentFile();
		if (p == null) {
			return null;
		}
		File pdf = new File(p + FILE_EXT);
		Document doc = new Document(pdf);
		
		return doc;
	}


	@Override
	public String toString() {
		return "Document [obj=" + (obj == null ? "" : obj.length()) + ", id=" + id + ", file=" + file
				+ ", flag=" + flag + ", modified=" + modified + ", order="
				+ order + ", changed=" + changed + "]";
	}

	public void setChanged(boolean b) {
		this.changed = b;
	}
	
	public boolean isChanged() {
		return this.changed;
	}

	public int getFlagIcon() {
		//TODO custom icon
		return MenuDialogs.mapFlagIcon(flag);
	}

	public int getTypeIcon() {
		// TODO custom type icon
		return 0;
	}

	public String getPath() {
		return file == null ? null : file.getPath();
	}

	public void update(JsonObject obj) throws Exception {
		this.obj = obj;
		init(obj);
		ContentHelper.saveObject(obj, file);
	}
}
